'use strict';

const path = require('path');
const pm2 = require('pm2');
const BaseService = require('../../libs/base/BaseService');
const fs = require('fs');

/**
 * Main服务，负责进程管理
 */
class Main extends BaseService {
  /**
   * 构造函数
   */
  constructor() {
    super('Main');

    this._processes = {};
    this._status = 'initialized';
    console.log(`[Main] 构造函数 isDebug=${this.isDebug}`);
  }

  /**
   * 初始化服务
   */
  async init() {
    // 连接PM2
    await this._connectToPM2();

    // 加载配置
    await this._loadConfig();

    // 启动所有进程
    await this._startAllProcesses();

    this._status = 'running';
    console.log('[Main] 服务初始化完成');
  }

  /**
   * 连接到PM2
   * @private
   */
  async _connectToPM2() {
    return new Promise((resolve, reject) => {
      pm2.connect((err) => {
        if (err) {
          console.error('[Main] 连接PM2失败:', err);
          return reject(err);
        }

        console.log('[Main] 已连接到PM2');
        resolve();
      });
    });
  }

  /**
   * 加载配置
   * @private
   */
  async _loadConfig() {
    try {
      const configPath = path.resolve(process.cwd(), 'config/server.json');
      const configContent = fs.readFileSync(configPath, 'utf8');
      const config = JSON.parse(configContent);

      this._config = config;
      console.log('[Main] 配置已加载');
    } catch (error) {
      console.error('[Main] 加载配置失败:', error);
      throw error;
    }
  }

  /**
   * 启动所有进程
   * @private
   */
  async _startAllProcesses() {
    const processes = this._config.processes;

    // 1. 先从配置中找到Logger进程
    const loggerProcess = processes.find(p => p.name === 'Logger');

    // 2. 如果存在Logger进程，先启动它
    if (loggerProcess) {
      try {
        console.log('[Main] 正在启动关键进程: Logger');
        for (let i = 0; i < loggerProcess.number; i++) {
          const port = loggerProcess.port + i;
          await this.startProcess(loggerProcess.name, port);
        }

        // 等待一段时间确保Logger进程完全启动
        await new Promise(resolve => setTimeout(resolve, 2000));
        console.log('[Main] Logger进程启动完成，现在可以安全使用日志功能');
      } catch (error) {
        console.error(`[Main] 启动Logger进程失败:`, error);
        throw new Error('无法启动Logger进程，终止启动流程');
      }
    }

    // 3. 启动其他进程(除了Main和Logger)
    for (const process of processes) {
      // 跳过Main进程（已在运行）和Logger进程（已启动）
      if (process.name === 'Main' || process.name === 'Logger') {
        continue;
      }

      try {
        console.log(`[Main] 正在启动进程: ${process.name}`);
        // 启动进程
        for (let i = 0; i < process.number; i++) {
          const port = process.port + i;
          await this.startProcess(process.name, port);
        }
      } catch (error) {
        console.error(`[Main] 启动进程 ${process.name} 失败:`, error);
      }
    }
  }

  /**
   * 启动进程
   * @param {string} processName 进程名称
   * @param {number} port 端口号
   * @returns {Promise<object>} 进程信息
   */
  async startProcess(processName, port) {
    return new Promise((resolve, reject) => {
      const processConfig = this._config.processes.find(p => p.name === processName);

      if (!processConfig) {
        return reject(new Error(`进程 ${processName} 配置不存在`));
      }

      const scriptPath = path.resolve(process.cwd(), `src/${processConfig.type}/init.js`);

      // 检查文件是否存在
      if (!fs.existsSync(scriptPath)) {
        return reject(new Error(`进程脚本 ${scriptPath} 不存在`));
      }

      // PM2进程名称
      const pm2Name = `${processName}-${port}`;

      // 设置环境变量
      const env = {
        NODE_ENV: this.isDebug ? 'development' : 'production',
        SERVICE_NAME: processName,
        SERVICE_PORT: port
      };

      // 添加调试参数
      let nodeArgs = [];

      // 检查是否有断点配置且处于调试模式
      if (this.isDebug && processConfig.breakPort) {
        const breakPort = processConfig.breakPort + (port - processConfig.port);
        env.BREAK_PORT = breakPort;

        // 使用增强的调试参数，确保正确工作
        nodeArgs = [`--inspect-brk=${breakPort}`];
        // 在日志中明确显示完整命令，便于调试
        console.log(`[Main] 进程 ${pm2Name} 开启调试模式，命令: node ${nodeArgs.join(' ')} ${scriptPath} ${processName} ${port}`);
      } else {
        console.log(`[Main] 进程 ${pm2Name} 以生产模式启动，不启用调试端口`);
      }

      // 配置PM2启动选项
      const startOptions = {
        name: pm2Name,
        script: scriptPath,
        args: `${processName} ${port}`,
        env: env,
        node_args: nodeArgs,
        kill_timeout: 3000   // 给进程足够的时间优雅退出
      };

      // 启动进程
      pm2.start(startOptions, (err, apps) => {
        if (err) {
          console.error(`[Main] 启动进程 ${pm2Name} 失败:`, err);
          return reject(err);
        }

        console.log(`[Main] 进程 ${pm2Name} 已启动`);

        // 存储进程信息
        this._processes[pm2Name] = {
          name: processName,
          port,
          pm2Name,
          status: 'running',
          startTime: Date.now(),
          breakPort: env.BREAK_PORT || null
        };

        resolve(this._processes[pm2Name]);
      });
    });
  }

  /**
   * 停止进程
   * @param {string} pm2Name PM2进程名称
   * @returns {Promise<boolean>} 是否成功
   */
  async stopProcess(pm2Name) {
    return new Promise((resolve, reject) => {
      // 检查进程是否存在
      if (!this._processes[pm2Name]) {
        return reject(new Error(`进程 ${pm2Name} 不存在`));
      }

      // 停止进程
      pm2.delete(pm2Name, (err) => {
        if (err) {
          console.error(`[Main] 停止进程 ${pm2Name} 失败:`, err);
          return reject(err);
        }

        console.log(`[Main] 进程 ${pm2Name} 已停止`);

        // 更新进程状态
        this._processes[pm2Name].status = 'stopped';

        resolve(true);
      });
    });
  }

  /**
   * 获取进程信息
   * @param {string} pm2Name PM2进程名称
   * @returns {object|null} 进程信息
   */
  async getProcessInfo(pm2Name) {
    return this._processes[pm2Name] || null;
  }

  /**
   * 停止服务
   */
  async stop() {
    // 停止所有进程
    for (const pm2Name in this._processes) {
      if (this._processes[pm2Name].status === 'running') {
        try {
          await this.stopProcess(pm2Name);
        } catch (error) {
          console.error(`[Main] 停止进程 ${pm2Name} 失败:`, error);
        }
      }
    }

    // 断开PM2连接
    pm2.disconnect();

    this._status = 'stopped';
    console.log('[Main] 服务已停止');
  }

  /**
   * 重启进程
   * @param {string} processName 进程名称
   * @param {number} port 端口号
   * @returns {Promise<object>} 进程信息
   */
  async restartProcess(processName, port) {
    const pm2Name = `${processName}-${port}`;

    try {
      // 检查进程是否存在
      if (!this._processes[pm2Name]) {
        throw new Error(`进程 ${pm2Name} 不存在`);
      }

      console.log(`[Main] 正在重启进程 ${pm2Name}`);

      // 先停止进程
      await this.stopProcess(pm2Name);

      // 等待一小段时间确保进程完全停止
      await new Promise(resolve => setTimeout(resolve, 1000));

      // 重新启动进程
      const processInfo = await this.startProcess(processName, port);

      console.log(`[Main] 进程 ${pm2Name} 重启完成`);

      return processInfo;
    } catch (error) {
      console.error(`[Main] 重启进程 ${pm2Name} 失败:`, error);
      throw error;
    }
  }
  /**
   * 设置进程状态
   * @param {string} processName 进程名称
   * @param {number} port 端口号
   * @param {number} status 状态信息：0=停滞，1=正常
   * @returns {Promise<object>} 进程信息
   */
  async setProcess(processName, port, status) {
    const pm2Name = `${processName}-${port}`;

    try {
      // 检查进程是否存在
      if (!this._processes[pm2Name]) {
        throw new Error(`进程 ${pm2Name} 不存在`);
      }

      console.log(`[Main] 正在更新进程状态 ${pm2Name}`);

      // 通知网关gateway/http 这个进程需要维护，可维持目前用户的信息交互，不再新增信息交互
      // await this.stopProcess(pm2Name);

      console.log(`[Main] 进程 ${pm2Name} 通知`);

      return true;
    } catch (error) {
      console.error(`[Main] 重启进程 ${pm2Name} 失败:`, error);
      throw error;
    }
  }
}

module.exports = Main; 